package com.example.wechat.service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.example.wechat.config.WebSocketEventListener;
import com.example.wechat.mapper.WechatConversationMemberMapper;
import com.example.wechat.model.WechatConversationMember;

@Service
public class WebSocketService {

	private static final Logger log = LoggerFactory.getLogger(WebSocketService.class);

	@Autowired
	private SimpMessageSendingOperations messagingTemplate;

	@Autowired
	private WebSocketEventListener webSocketEventListener;


	@Autowired
	private WechatConversationMemberMapper conversationMemberMapper;

	/**
	 * 推送新消息给接收者
	 */
	@Transactional
	public void pushNewMessage(String receiverUserId, Map<String, String> messageData) {
		try {
			String receiverId = receiverUserId.toString();

			// 检查接收者是否在线
			if (webSocketEventListener.isUserOnline(receiverId)) {
				// 在线用户：通过WebSocket实时推送
				pushViaWebSocket(receiverId, messageData);
				log.info("实时推送消息给用户: {}", receiverId);
			}

		} catch (Exception e) {
			log.error("推送消息失败, receiver: {}, error: {}", receiverUserId, e.getMessage(), e);
			throw new RuntimeException("消息推送失败", e);
		}
	}

	/**
	 * 通过WebSocket实时推送
	 */
	private void pushViaWebSocket(String receiverId, Map<String, String> messageData) {
		try {
			// 发送到用户专属队列
			String destination = "/queue/user/" + receiverId + "/messages";
			messagingTemplate.convertAndSend(destination, messageData);

			// 同时发送到会话主题，用于多端同步
			String conversationId = (String) messageData.get("conversationId");
			if (conversationId != null) {
				String topicDestination = "/topic/conversation/" + conversationId;
				messagingTemplate.convertAndSend(topicDestination, messageData);
			}

		} catch (Exception e) {
			log.error("WebSocket推送失败, receiver: {}", receiverId, e);
			throw e;
		}
	}

	/**
	 * 推送消息已读状态
	 */
	public void pushMessageReadStatus(String conversationId, String readerUserId, Long messageId, Integer unreadCount) {
		Map<String, Object> readData = Map.of("type", "message_read", "conversationId", conversationId, "readerId",
				readerUserId, "messageId", messageId, "unreadCount", unreadCount, "timestamp",
				System.currentTimeMillis());

		// 发送到会话主题
		messagingTemplate.convertAndSend("/topic/conversation/" + conversationId, readData);
	}

	/**
	 * 推送用户输入状态
	 */
	public void pushTypingStatus(String conversationId, String userId, boolean isTyping) {
		Map<String, Object> typingData = Map.of("type", "typing", "conversationId", conversationId, "userId", userId,
				"isTyping", isTyping, "timestamp", System.currentTimeMillis());

		messagingTemplate.convertAndSend("/topic/conversation/" + conversationId, typingData);
	}

	/**
	 * 推送消息撤回通知
	 * 
	 * @param conversationId 会话ID (对应数据库BIGINT类型)
	 * @param messageId      被撤回的消息ID (对应数据库BIGINT类型)
	 * @param userId         执行撤回操作的用户ID (对应数据库BIGINT类型)
	 */
	public void pushMessageRecall(Long conversationId, Long messageId, Long userId) {
		try {
			log.info("推送消息撤回通知: conversationId={}, messageId={}, userId={}", conversationId, messageId, userId);

			// 构建撤回消息的数据包
			Map<String, Object> recallData = new HashMap<>();
			recallData.put("type", "message_recall");
			recallData.put("conversationId", conversationId);
			recallData.put("messageId", messageId);
			recallData.put("recalledBy", userId);
			recallData.put("recallTime", System.currentTimeMillis());
			recallData.put("displayText", "该消息已被撤回");

			// 1. 通过WebSocket实时推送撤回指令给会话中的所有在线成员
			String topicDestination = "/topic/conversation/" + conversationId;
			messagingTemplate.convertAndSend(topicDestination, recallData);

			// 2. 针对每个会话成员进行点对点推送（确保多端同步）
			List<WechatConversationMember> members = conversationMemberMapper.findByConversationId(conversationId);

			for (WechatConversationMember member : members) {
				String userDestination = "/queue/user/" + member.getUserId() + "/recall";
				messagingTemplate.convertAndSend(userDestination, recallData);

				log.debug("消息撤回通知已发送给用户: {}", member.getUserId());
			}

			log.info("消息撤回通知推送完成: messageId={}", messageId);

		} catch (Exception e) {
			log.error("推送消息撤回通知失败: conversationId={}, messageId={}, error={}", conversationId, messageId,
					e.getMessage(), e);
			// 可以根据需要抛出运行时异常或进行重试逻辑
			throw new RuntimeException("消息撤回通知发送失败", e);
		}
	}
}